from flask import jsonify, request, g
from flask.views import MethodView

from app.apis.v1 import api_v1
from app.models import User, Crawler, Category, Record
from app.extensions import db
from app.apis.v1.schemas import user_schema, crawler_schema, category_schema, records_schema
from app.apis.v1.errors import api_abort
from app.apis.v1.auth import generate_token


def get_data(key):
    if request.get_json():
        return request.get_json().get(key)
    return None


class UserAPI(MethodView):

    def get(self):
        if g.current_user:
            return user_schema(g.current_user)
        return jsonify(code=401, message='You haven\'t logged in yet!')

    def post(self):
        profile = get_data('data')
        username = profile.get('username')
        existed = User.query.filter_by(username=username)
        if existed:
            return jsonify(code=400, message='This user is existed!')
        email = profile.get('email')
        password = profile.get('password')
        user = User(username=username, email=email)
        user.set_password(password)
        db.session.add(user)
        db.session.commit()
        return jsonify(code=200, message='User has been registered successfully!')


class CrawlerAPI(MethodView):

    def get(self):
        crawler_id = request.args.get('crawlerId')
        crawler = Crawler.query.get_or_404(crawler_id)
        return crawler_schema(crawler)


class RecordAPI(MethodView):
    def get(self):
        crawler_id = request.args.get('crawlerId')
        page = request.args.get('page', 1, type=int)
        pagination = Record.query.filter_by(crawler_id=crawler_id).paginate(page, per_page=10)
        items = pagination.items
        results = records_schema(items, pagination)
        return jsonify(results)


class CategoryAPI(MethodView):
    def get(self):
        category_id = request.args.get('categoryId')
        category = Category.query.get_or_404(category_id)
        return category_schema(category)

    def post(self):
        title = get_data('title')
        existed = Category.query.filter_by(title=title).first()
        if existed:
            return jsonify(code=400, message='This category is existed!')
        category = Category(title=title)
        db.session.add(category)
        db.session.commit()
        return jsonify(code=200, message='{} has been created successfully'.format(title))


class AuthTokenAPI(MethodView):

    def post(self):
        grant_type = request.form.get('grant_type')
        username = request.form.get('username')
        password = request.form.get('password')

        if grant_type is None or grant_type.lower() != 'password':
            return api_abort(code=400, message='The grant type must be password.')

        user = User.query.filter_by(username=username).first()
        if user is None or not user.validate_password(password):
            return api_abort(code=400, message='Either the username or password was invalid.')

        token, expiration = generate_token(user)

        response = jsonify({
            'token': token,
            'token_type': 'Bearer',
            'username': username,
            'id': user.id,
            'expires_in': expiration
        })
        response.headers['Cache-Control'] = 'no-store'
        response.headers['Pragma'] = 'no-cache'
        return response


api_v1.add_url_rule('/oauth/token', view_func=AuthTokenAPI.as_view('token'), methods=['POST'])
api_v1.add_url_rule('/user', view_func=UserAPI.as_view('user'), methods=['GET', 'POST'])
api_v1.add_url_rule('/crawler', view_func=CrawlerAPI.as_view('crawler'), methods=['GET'])
api_v1.add_url_rule('/record', view_func=RecordAPI.as_view('record'), methods=['GET'])
api_v1.add_url_rule('/category', view_func=CategoryAPI.as_view('category'), methods=['GET', 'POST'])
